package axelrod;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import java.io.File;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;


public class UserInterface extends JFrame {
    private int numOfAgents;
    private int numOfTurns;
    
    private String imageDirectory = "." + File.separator + "images" + 
        File.separator;
    
    private BorderLayout layoutMain = new BorderLayout();
    private JToolBar toolBar = new JToolBar();
    private JButton buttonStart = new JButton();
    private JButton buttonNext = new JButton();
    private ImageIcon imageStart = new ImageIcon(imageDirectory + "play.png");
    private ImageIcon imageNext = new ImageIcon(imageDirectory + "next.png");
    private JSplitPane splitPanel = new JSplitPane();
    private JScrollPane agentsPane = new JScrollPane();
    private JScrollPane actionsPane = new JScrollPane();
    private JTable scoresTable;
    private JTable actionsTable;

    private transient Environment env;
    private BorderLayout borderLayout1 = new BorderLayout();
    private BorderLayout borderLayout2 = new BorderLayout();

    /** Creates the user interface used to visualise the tournament.
     * @param numOfAgents the number of agents in the tournament.
     * @param numOfTurns the number of turns for each match.
     * @param agents the agents specifier strings.
     */
    public UserInterface(int numOfAgents, int numOfTurns, String[] agents) {
        this.numOfAgents = numOfAgents;
        this.numOfTurns = numOfTurns;
        env = new Environment(numOfAgents, numOfTurns, agents, this);
        try {
            buildScoresTable(agents);
            buildActionsTable();
            jbInit();
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void jbInit() throws Exception {
        this.getContentPane().setLayout( layoutMain );
        this.setSize(new Dimension(501, 353));
        this.setTitle( "Axelord Simulation" );
        buttonStart.setToolTipText("Run tournament");
        buttonStart.setIcon( imageStart );
        buttonStart.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    buttonStart_mouseClicked(e);
                }
            });
        buttonNext.setToolTipText("Step by step");
        buttonNext.setIcon( imageNext );
        buttonNext.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    buttonNext_mouseClicked(e);
                }
            });
        splitPanel.setDividerLocation(301);
       // splitPanel.setSize(new Dimension(500, 319));
        splitPanel.setEnabled(false);
        agentsPane.getViewport().setLayout(borderLayout1);
        actionsPane.getViewport().setLayout(borderLayout2);
        //scoresTable.setSize(new Dimension(300, 300));
       // scoresTable.setPreferredSize(new Dimension(255, 300));
       // scoresTable.setBounds(new Rectangle(0, 0, 180, 300));
        //actionsTable.setPreferredSize(new Dimension(170, 300));
     //   actionsTable.setBounds(new Rectangle(0, 0, 80, 300));
        //actionsTable.setSize(new Dimension(200, 300));
        toolBar.add( buttonStart );
        toolBar.add( buttonNext );
        this.getContentPane().add( toolBar, BorderLayout.NORTH );
        agentsPane.getViewport().add(scoresTable, null);
        splitPanel.add(agentsPane, JSplitPane.LEFT);
        actionsPane.getViewport().add(actionsTable, null);
        splitPanel.add(actionsPane, JSplitPane.RIGHT);
        this.getContentPane().add(splitPanel, BorderLayout.CENTER);

    }
    
    void updateActions(int firstMove, int secondMove,  int turn) {
        updateActionsCell(firstMove, turn, 0);
        updateActionsCell(secondMove, turn, 1);
    }

    void updateActionsCell(int move, int turn, int player) {
      if(move == Environment.MOVE_COOPERATE) {
        actionsTable.getModel().setValueAt("COOPERATE", turn, player);
      } else {
        actionsTable.getModel().setValueAt("DEFECT", turn, player);
      }
    }
    
    void updateScores(int firstAgent, int secondAgent, int firstScore,
                      int secondScore) {
        updateScore(firstAgent, firstScore);
        updateScore(secondAgent, secondScore);
    }
    
    private void updateScore(int agent, int score) {
        //set the agent column to indicate end of play
        if(agent >= scoresTable.getRowCount()) {
            return;
        }
        DefaultTableModel md = (DefaultTableModel)scoresTable.getModel();
        md.setValueAt("agent" + agent, agent, 0);
        //set the score for the agent
        md.setValueAt(score , agent, 2);
    }
    
    private void buildScoresTable(String[] agents) {
          Object[][] Data = new Object[agents.length][3];
          String[] columnNames = {"Agent Name", "Agent Type", "Score"};
          for(int i = 0; i < Data.length;i++) {
              Data[i] = new Object[3];
              Data[i][0] = "agent" + i;
              Data[i][1] = agents[i];
              Data[i][2] = 0;
          }
          DefaultTableModel dm = new DefaultTableModel(Data, columnNames);
          scoresTable = new JTable(dm);
    }
    
    private void buildActionsTable() {
        Object[][] Data = new Object[numOfTurns][2];
        String[] columnNames = {"First Agent", "Second Agent"};
        for(int i = 0;i < Data.length;i++) {
            Data[i] = new Object[2];
            Data[i][0] = "";
            Data[i][1] = "";
        }
        DefaultTableModel dm = new DefaultTableModel(Data, columnNames);
        actionsTable = new JTable(dm);
    }
    
    public static void main(String[] args) {
        final String[] agentsDefault = 
            {Environment.ALLD_AGENT, Environment.TIT_AGENT, 
              Environment.TES_AGENT, Environment.JOS_AGENT};
        if(args.length == 0) {
            //run with default parameters
            startInterface(4, 10, agentsDefault);
        } else {
            int na, nt;
            try {
                na = Integer.parseInt(args[0]);
                nt = Integer.parseInt(args[1]);
                if(args.length != 2 + na) {
                    startInterface(4, 10, agentsDefault);
                } else {
                    final String[] agents = new String[na];    
                    for(int i = 0;i < na;i++) {
                        agents[i] = args[i + 2];
                    }
                    startInterface(na, nt, agents);
                }
                
            } catch(NumberFormatException e) {
                startInterface(4, 10, agentsDefault);
            }
        }
    }

    private static void startInterface(final int numberOfAgents, 
                                final int numberOfTurns, 
                                final String[] agents) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
              UserInterface inter = new UserInterface(numberOfAgents, 
                                                      numberOfTurns, agents);
              inter.setVisible(true);
            }
        });                   
    }
    
    private void buttonStart_mouseClicked(MouseEvent e) {
        env.startTournament();
    }   

    void updatePlaying(int firstAgent, int secondAgent) {
        //set the names in the scores table to reflect what agents are playing
        if(secondAgent >= scoresTable.getRowCount()) {
            return;
        }
        DefaultTableModel dm = (DefaultTableModel)actionsTable.getModel();
        scoresTable.getModel().setValueAt("agent" + firstAgent + 
                                          "(now playing)", firstAgent, 0);
        scoresTable.getModel().setValueAt("agent" + secondAgent + 
                                        "(now playing)", secondAgent, 0);
        for(int i =0;i < numOfTurns;i++) {
            dm.setValueAt("", i, 0);
            dm.setValueAt("", i, 1);
        }
    }

    private void buttonNext_mouseClicked(MouseEvent e) {
        env.startMatch();
    }

    void displayWinner(int result) {
        JOptionPane.showMessageDialog(this, "agent" + result +" has won");
    }
}
